home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cvs / sprite / save / update.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-29  |  13.8 KB  |  528 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: update.c,v 1.27.1.2 91/02/06 18:30:07 berliner Exp $";
  3. #endif !lint
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  *    "update" updates the version in the present directory with respect to
  12.  *    the RCS repository.  The present version must have been created by
  13.  *    "checkout".  The user can keep up-to-date by calling "update" whenever
  14.  *    he feels like it.
  15.  *
  16.  *    The present version can be committed by "commit", but this keeps the
  17.  *    version in tact.
  18.  *
  19.  *    "update" accepts the following options:
  20.  *        -p    Prunes empty directories
  21.  *        -l    Local; does not do a recursive update
  22.  *        -q    Quiet; does not print a message when
  23.  *                recursively updating
  24.  *        -Q    Really quiet
  25.  *        -d    Directory; causes update to create new directories
  26.  *                as they are added to the RCS repository
  27.  *        -f    Forces a match for the -r revision
  28.  *        -r tag    Revision; only extract from revision "tag"
  29.  *        -D date    Updates to the revision specified by "date"
  30.  *
  31.  *    Arguments following the options are taken to be file names
  32.  *    to be updated, rather than updating the entire directory.
  33.  *
  34.  *    Modified or non-existent RCS files are checked out and reported
  35.  *    as U <user_file>
  36.  *
  37.  *    Modified user files are reported as M <user_file>.  If both the
  38.  *    RCS file and the user file have been modified, the user file
  39.  *    is replaced by the result of rcsmerge, and a backup file is
  40.  *    written for the user in .#file.version.  If this throws up
  41.  *    irreconcilable differences, the file is reported as C <user_file>,
  42.  *    and as M <user_file> otherwise.
  43.  *
  44.  *    Files added but not yet committed are reported as A <user_file>.
  45.  *    Files removed but not yet decommitted are reported as R <user_file>.
  46.  *
  47.  *    If the current directory contains subdirectories that hold
  48.  *    concurrent versions, these are updated too.  If the -d option
  49.  *    was specified, new directories added to the repository are
  50.  *    automatically created and updated as well.
  51.  */
  52.  
  53. #include <sys/param.h>
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56. #include <dirent.h>
  57. #include "cvs.h"
  58.  
  59. char update_dir[MAXPATHLEN];
  60. int update_recursive = 1;
  61. int update_build_dirs = 0;
  62. int update_prune_dirs = 0;
  63.  
  64. static int really_recursive = 1;
  65.  
  66. update(argc, argv)
  67.     int argc;
  68.     char *argv[];
  69. {
  70.     FILE *fp;
  71.     int c, err = 0;
  72.  
  73.     if (argc == -1)
  74.     update_usage();
  75.     optind = 1;
  76.     while ((c = getopt(argc, argv, "pflQqdr:D:")) != -1) {
  77.     switch (c) {
  78.     case 'l':
  79.         really_recursive = 0;
  80.         update_recursive = 0;
  81.         break;
  82.     case 'Q':
  83.         really_quiet = 1;
  84.         /* FALL THROUGH */
  85.     case 'q':
  86.         quiet = 1;
  87.         break;
  88.     case 'd':
  89.         update_build_dirs = 1;
  90.         break;
  91.     case 'f':
  92.         force_tag_match = 1;
  93.         break;
  94.     case 'r':
  95.         (void) strcpy(Tag, optarg);
  96.         break;
  97.     case 'D':
  98.         Make_Date(optarg, Date);
  99.         break;
  100.     case 'p':
  101.         update_prune_dirs = 1;
  102.         break;
  103.     case '?':
  104.     default:
  105.         update_usage();
  106.         break;
  107.     }
  108.     }
  109.     argc -= optind;
  110.     argv += optind;
  111.     if (!isdir(CVSADM)) {
  112.     if (!quiet)
  113.         warn(0, "warning: no %s directory found", CVSADM);
  114.     if (argc <= 0) {
  115.         err += update_descend(update_recursive);
  116.     } else {
  117.         int i;
  118.  
  119.         for (i = 0; i < argc; i++) {
  120.         if (isdir(argv[i])) {
  121.             (void) strcat(Dlist, " ");
  122.             (void) strcat(Dlist, argv[i]);
  123.         } else {
  124.             warn(0, "nothing known about %s", argv[i]);
  125.             err++;
  126.         }
  127.         }
  128.         err += update_process_lists();
  129.     }
  130.     return (err);
  131.     }
  132.     Name_Repository();
  133.     Reader_Lock();
  134.     if (argc <= 0) {
  135.     /*
  136.      * When updating the entire directory, and recursively building
  137.      * directories, must make sure that the "static" file in the
  138.      * administration is removed before calling Find_Names().
  139.      */
  140.     if (update_build_dirs)
  141.         (void) unlink(CVSADM_ENTSTAT);
  142.     if (force_tag_match && (Tag[0] != '\0' || Date[0] != '\0'))
  143.         Find_Names(&fileargc, fileargv, ALLPLUSATTIC);
  144.     else
  145.         Find_Names(&fileargc, fileargv, ALL);
  146.     fp = open_file(CVSADM_MOD, "w+"); /* create a NULL Mod file */
  147.     (void) fclose(fp);
  148.     argc = fileargc;
  149.     argv = fileargv;
  150.     } else {
  151.     /*
  152.      * Not recursive if files were specified on the command line
  153.      */
  154.     update_recursive = 0;
  155.     }
  156.     if (Collect_Sets(argc, argv) != 0)
  157.     error(0, "failed; correct the above errors first");
  158.     free_names(&fileargc, fileargv);
  159.     err += update_process_lists();
  160.     /*
  161.      * XXX - Might be nice to sort the Mod file here, removing unique
  162.      * entries as we go, but it's currently not necessary, as "diff"
  163.      * is the only one that uses it, and he does the sort "as needed".
  164.      */
  165.     Lock_Cleanup(0);
  166.     /*
  167.      * Make directories, and descend them if requested to.
  168.      */
  169.     err += update_make_dirs(update_build_dirs && update_recursive);
  170.     err += update_descend(update_recursive);
  171.     Lock_Cleanup(0);
  172.     return (err);
  173. }
  174.  
  175. /*
  176.  * Process the lists created by Collect_Sets().
  177.  */
  178. static
  179. update_process_lists()
  180. {
  181.     char backup[MAXPATHLEN], dlist[MAXLISTLEN];
  182.     FILE *fp;
  183.     char *cp;
  184.     int update_Files = 0, err = 0;
  185.  
  186.     /*
  187.      * Wlist is the "remove entry" list.
  188.      */
  189.     for (cp = strtok(Wlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  190.     update_Files = 1;
  191.     (void) strcpy(User, cp);
  192.     Scratch_Entry(User);
  193.     (void) unlink(User);
  194.     }
  195.     /*
  196.      * Olist is the "needs checking out" list.
  197.      */
  198.     for (cp = strtok(Olist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  199.     update_Files = 1;
  200.     (void) strcpy(User, cp);
  201.     Locate_RCS();
  202.     (void) sprintf(backup, "%s/%s%s", CVSADM, CVSPREFIX, User);
  203.     if (isreadable(User))
  204.         rename_file(User, backup);
  205.     else
  206.         (void) unlink(backup);
  207.     if (Tag[0] != '\0' || Date[0] != '\0') {
  208.         Version_Number(Rcs, Tag, Date, VN_Rcs);
  209.         (void) sprintf(prog, "%s/%s -q -r%s %s %s", Rcsbin, RCS_CO,
  210.                VN_Rcs, Rcs, User);
  211.     } else {
  212.         (void) sprintf(prog, "%s/%s -q %s %s", Rcsbin, RCS_CO, Rcs, User);
  213.     }
  214.     if (system(prog) == 0) {
  215.         if (cvswrite == TRUE)
  216.         xchmod(User, 1);
  217.         Version_TS(Rcs, Tag, User);
  218.         Register(User, VN_Rcs, TS_User);
  219.         if (!really_quiet) {
  220.         if (update_dir[0])
  221.             printf("U %s/%s\n", update_dir, User);
  222.         else
  223.             printf("U %s\n", User);
  224.         }
  225.     } else {
  226.         if (isreadable(backup))
  227.         rename_file(backup, User);
  228.         warn(0, "could not check out %s", User);
  229.         err++;
  230.     }
  231.     (void) unlink(backup);
  232.     }
  233.     /*
  234.      * Mlist is the "modified, needs checking in" list.
  235.      */
  236.     for (cp = strtok(Mlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  237.     update_Files = 1;
  238.     (void) strcpy(User, cp);
  239.     if (!really_quiet) {
  240.         if (update_dir[0])
  241.         printf("M %s/%s\n", update_dir, User);
  242.         else
  243.         printf("M %s\n", User);
  244.     }
  245.     fp = open_file(CVSADM_MOD, "a");
  246.     if (fprintf(fp, "%s\n", User) == EOF)
  247.         error(1, "cannot write %s", CVSADM_MOD);
  248.     (void) fclose(fp);
  249.     }
  250.     /*
  251.      * Alist is the "to be added" list.
  252.      */
  253.     for (cp = strtok(Alist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  254.     update_Files = 1;
  255.     (void) strcpy(User, cp);
  256.     if (!really_quiet) {
  257.         if (update_dir[0])
  258.         printf("A %s/%s\n", update_dir, User);
  259.         else
  260.         printf("A %s\n", User);
  261.     }
  262.     }
  263.     /*
  264.      * Rlist is the "to be removed" list.
  265.      */
  266.     for (cp = strtok(Rlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  267.     update_Files = 1;
  268.     (void) strcpy(User, cp);
  269.     if (!really_quiet) {
  270.         if (update_dir[0])
  271.         printf("R %s/%s\n", update_dir, User);
  272.         else
  273.         printf("R %s\n", User);
  274.     }
  275.     }
  276.     /*
  277.      * Glist is the "modified, needs merging" list.
  278.      *
  279.      * The users currently modified file is moved to a backup file
  280.      * name ".#filename.version", so that it will stay around for about
  281.      * three days before being automatically removed by some cron
  282.      * daemon.  The "version" is the version of the file that the
  283.      * user was most up-to-date with before the merge.
  284.      */
  285.     for (cp = strtok(Glist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  286.     update_Files = 1;
  287.     (void) strcpy(User, cp);
  288.     Locate_RCS();
  289.     Version_TS(Rcs, Tag, User);
  290.     (void) sprintf(backup, "%s%s.%s", BAKPREFIX, User, VN_User);
  291.     (void) unlink(backup);
  292.     copy_file(User, backup);
  293.     xchmod(User, 1);
  294.     (void) sprintf(prog, "%s/%s -r%s %s", Rcsbin, RCS_MERGE,
  295.                VN_User, Rcs);
  296.     if (system(prog) != 0) {
  297.         warn(0, "could not merge revision %s of %s",
  298.          VN_User, User);
  299.         warn(0, "backup file for %s is in %s", User, backup);
  300.         err++;
  301.         continue;
  302.     }
  303.     Register(User, VN_Rcs, TS_Rcs);
  304.     (void) sprintf(prog, "%s -s '%s' %s", GREP, RCS_MERGE_PAT, User);
  305.     if (system(prog) == 0) {
  306.         warn(0, "conflicts found in %s", User);
  307.         if (!really_quiet) {
  308.         if (update_dir[0])
  309.             printf("C %s/%s\n", update_dir, User);
  310.         else
  311.             printf("C %s\n", User);
  312.         }
  313.     } else {
  314.         if (!really_quiet) {
  315.         if (update_dir[0])
  316.             printf("M %s/%s\n", update_dir, User);
  317.         else
  318.             printf("M %s\n", User);
  319.         }
  320.     }
  321.     fp = open_file(CVSADM_MOD, "a");
  322.     if (fprintf(fp, "%s\n", User) == EOF)
  323.         error(1, "cannot write %s", CVSADM_MOD);
  324.     (void) fclose(fp);
  325.     }
  326.     /*
  327.      * Slist is a list of symbolic links that need to be created.
  328.      */
  329.     for (cp = strtok(Slist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  330.     char     tmp[MAXPATHLEN];
  331.     char     src[MAXPATHLEN];
  332.     int    size;
  333.     (void) strcpy(User, cp);
  334.     (void) sprintf(tmp, "%s/%s", Repository, User);
  335.     size = readlink(tmp, src, MAXPATHLEN);
  336.     if (size == -1) {
  337.         error(1, "readlink of %s failed", tmp);
  338.     }
  339.     src[size] = '\0';
  340.     if (symlink(src, User) != 0) {
  341.         error(1, "symlink of %s to %s failed", User, src);
  342.     }
  343.     if (!really_quiet) {
  344.         printf("S %s\n", User);
  345.     }
  346.     }
  347.     if (Dlist[0]) {
  348.     int save_recursive = update_recursive;
  349.  
  350.     update_recursive = really_recursive;
  351.     Lock_Cleanup(0);        /* cleanup locks before descending */
  352.     (void) strcpy(dlist, Dlist);    /* to get it on the stack... */
  353.     for (cp = strtok(dlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  354.         err += update_descend_dir(cp);
  355.     }
  356.     update_recursive = save_recursive;
  357.     }
  358.     if (update_Files != 0)
  359.     Entries2Files();
  360.     return (err);
  361. }
  362.  
  363. /*
  364.  * When automatically creating directories from the repository in the
  365.  * local work directory, we scan for directories that don't exist locally
  366.  * and create them with a NULL administration directory for now, which
  367.  * is filled by update later.
  368.  */
  369. static
  370. update_make_dirs(doit)
  371.     int doit;
  372. {
  373.     char fname[MAXPATHLEN], tmp[MAXPATHLEN];
  374.     DIR *dirp;
  375.     struct dirent *dp;
  376.     int err = 0;
  377.  
  378.     if (doit) {
  379.     if ((dirp = opendir(Repository)) == NULL) {
  380.         warn(0, "cannot open directory %s", Repository);
  381.         err++;
  382.     } else while ((dp = readdir(dirp)) != NULL) {
  383.         if (strcmp(dp->d_name, ".") == 0 ||
  384.         strcmp(dp->d_name, "..") == 0 ||
  385.         strcmp(dp->d_name, CVSATTIC) == 0 ||
  386.         strcmp(dp->d_name, CVSLCK) == 0)
  387.         continue;
  388.         (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
  389.         (void) sprintf(tmp, "%s/%s", dp->d_name, CVSADM);
  390.         if (!isdir(fname))
  391.         continue;
  392.         if (islink(dp->d_name) || isdir(tmp))
  393.         continue;
  394.         if (!isdir(dp->d_name) && isfile(dp->d_name)) {
  395.         warn(0, "file %s should be a directory; please move it", dp->d_name);
  396.         err++;
  397.         } else {
  398.         make_directory(dp->d_name);
  399.         if (chdir(dp->d_name) < 0) {
  400.             warn(0, "cannot chdir to %s", dp->d_name);
  401.             err++;
  402.         } else {
  403.             (void) strcpy(tmp, Repository);
  404.             (void) strcpy(Repository, fname);
  405.             Create_Admin(Repository, DFLT_RECORD);
  406.             (void) chdir("..");
  407.             (void) strcpy(Repository, tmp);
  408.         }
  409.         }
  410.     }
  411.     if (dirp)
  412.         (void) closedir(dirp);
  413.     }
  414.     return (err);
  415. }
  416.  
  417. /*
  418.  * If doalldirs is set, does a recursive update by calling update_descend_dir()
  419.  * for each file in the current directory.
  420.  */
  421. static
  422. update_descend(doalldirs)
  423.     int doalldirs;
  424. {
  425.     DIR *dirp;
  426.     struct dirent *dp;
  427.     int err = 0;
  428.  
  429.     if (doalldirs) {
  430.     if ((dirp = opendir(".")) == NULL) {
  431.         err++;
  432.     } else {
  433.         while ((dp = readdir(dirp)) != NULL) {
  434.         if (strcmp(dp->d_name, ".") == 0 ||
  435.             strcmp(dp->d_name, "..") == 0)
  436.             continue;
  437.         err += update_descend_dir(dp->d_name);
  438.         }
  439.         (void) closedir(dirp);
  440.     }
  441.     }
  442.     return (err);
  443. }
  444.  
  445. /*
  446.  * This is the recursive function that walks the argument directory looking
  447.  * for sub-directories that have CVS administration files in them
  448.  * and updates them recursively.
  449.  *
  450.  * Note that we do not follow symbolic links here, which is a feature!
  451.  */
  452. static
  453. update_descend_dir(dir)
  454.     char *dir;
  455. {
  456.     char cwd[MAXPATHLEN], fname[MAXPATHLEN];
  457.     char *cp;
  458.     int err;
  459.  
  460.     (void) sprintf(fname, "%s/%s", dir, CVSADM);
  461.     if (!isdir(dir) || islink(dir) || !isdir(fname))
  462.     return (0);
  463.     if (getwd(cwd) == NULL) {
  464.     warn(0, "cannot get working directory: %s", cwd);
  465.     return (1);
  466.     }
  467.     if (update_dir[0] == '\0')
  468.     (void) strcpy(update_dir, dir);
  469.     else {
  470.     (void) strcat(update_dir, "/");
  471.     (void) strcat(update_dir, dir);
  472.     }
  473.     if (!quiet)
  474.     printf("%s %s: Updating %s\n", progname, command, update_dir);
  475.     if (chdir(dir) < 0) {
  476.     warn(1, "cannot chdir to %s", update_dir);
  477.     err = 1;
  478.     goto out;
  479.     }
  480.     err = update(0, (char **)0);
  481.     if ((cp = rindex(update_dir, '/')) != NULL)
  482.     *cp = '\0';
  483.     else
  484.     update_dir[0] = '\0';
  485. out:
  486.     if (chdir(cwd) < 0)
  487.     error(1, "cannot chdir to %s", cwd);
  488.     if (update_prune_dirs && isemptydir(dir)) {
  489.     (void) sprintf(prog, "%s -fr %s", RM, dir);
  490.     (void) system(prog);
  491.     }
  492.     return (err);
  493. }
  494.  
  495. /*
  496.  * Returns 1 if the argument directory is completely empty, other than
  497.  * the existence of the CVS.adm directory entry.  Zero otherwise.
  498.  */
  499. isemptydir(dir)
  500.     char *dir;
  501. {
  502.     DIR *dirp;
  503.     struct dirent *dp;
  504.  
  505.     if ((dirp = opendir(dir)) == NULL) {
  506.         warn(0, "cannot open directory %s for empty check", dir);
  507.     return (0);
  508.     }
  509.     while ((dp = readdir(dirp)) != NULL) {
  510.         if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 &&
  511.             strcmp(dp->d_name, CVSADM) != 0) {
  512.             (void) closedir(dirp);
  513.             return (0);
  514.         }
  515.     }
  516.     (void) closedir(dirp);
  517.     return (1);
  518. }
  519.  
  520. static
  521. update_usage()
  522. {
  523.     (void) fprintf(stderr,
  524.            "Usage: %s %s [-Qqlfp] [-d] [-r tag|-D date] [files...]\n",
  525.            progname, command);
  526.     exit(1);
  527. }
  528.